package nccloud.api.testcase.base;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;

import com.google.gson.Gson;

import nccloud.api.test.utils.CompressUtil;
import nccloud.api.test.utils.Decryption;
import nccloud.api.test.utils.Encryption;
import nccloud.api.test.utils.ResultMessageUtil;
import nccloud.api.test.utils.SHA256Util;


/**
 * 测试
 *
 * @author Reno
 * @date 2021/12/16
 */
public class Test {

	/** 客户的秘密 */// app_secret
	private static String client_secret = null;
	/** 酒吧的关键 */// 公钥
	private static String pubKey = null;
	/** 客户机id */// app_id
	private static String client_id = null;
	/** 用户名 */// ncc用户名
	private static String username = null;
	/** 松材线虫病 */// ncc用户名密码
	private static String pwd = null;
	/** 商业中心 */// ncc账套
	private static String busi_center = null;
	/** 格兰特类型 */// 获取token方式：client_credentials、password
	private static String grant_type = null;
	/** 基url */// 服务器ip：port
	private static String baseUrl = null;
	/** 秘密级别 */// 返回值压缩加密级别
	private static String secret_level = null;
	/** 请求体 */// 请求参数
	private static String requestBody = null;
	/** api的url */// openapi请求路径
	private static String apiUrl = null;

	/** 令牌 */// 访问api获取到的access_token
	public static String token = null;
	/** 重复检查 */// 重复调用检查
	public static String repeat_check = null;
	/** 商业标识 */// 接口调用业务标识
	public static String busi_id = null;

	/**
	 * 主要
	 * 启动入口
	 *
	 * @param args arg游戏
	 */
	public static void main(String[] args) {
		try {
			// 初始化数据
			init();
			// 请求token
			token = getToken();
			System.out.println("getTokenData:" + token);
			if (token != null) {
				// 测试openapi
				testApi(token);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获得令牌
	 * 获取access_token
	 *
	 * @return {@link String}
	 * @throws Exception 异常
	 */
	private static String getToken() throws Exception {
		String token = null;
		if ("password".equals(grant_type)) {
			// 密码模式
			token = getTokenByPWD();
		} else if ("client_credentials".equals(grant_type)) {
			// 客户端模式
			token = getTokenByClient();
		}
		return token;
	}

	/**
	 * 获得令牌的客户
	 * 客户端模式获取token
	 *
	 * @return {@link String}
	 * @throws Exception 异常
	 */
	private static String getTokenByClient() throws Exception {
		Map<String, String> paramMap = new HashMap<String, String>();
		// 密码模式认证
		paramMap.put("grant_type", "client_credentials");
		// 第三方应用id
		paramMap.put("client_id", client_id);
		// 第三方应用secret 公钥加密
		paramMap.put("client_secret", URLEncoder.encode(Encryption.pubEncrypt(pubKey.trim(), client_secret), "utf-8"));
		// 账套编码
		paramMap.put("biz_center", busi_center);
		// // TODO 传递数据源和ncc登录用户
		//paramMap.put("dsname", "NCC2005");
		 paramMap.put("dsname", "design");
		 paramMap.put("usercode", "yonyou01");

		// 签名
		String sign = SHA256Util.getSHA256(client_id + client_secret + pubKey);
		paramMap.put("signature", sign);

		String url = baseUrl + "/nccloud/opm/accesstoken";
		String mediaType = "application/x-www-form-urlencoded";
		String token = doPost(url, paramMap, mediaType, null, "");
		return token;
	}


	/**
	 * 被pwd令牌
	 * 测试
	 *
	 * @return {@link String}
	 * @throws Exception 异常
	 */
	@SuppressWarnings("unused")
	private static String getTokenByPWD() throws Exception {
		Map<String, String> paramMap = new HashMap<String, String>();
		// 密码模式认证
		paramMap.put("grant_type", "password");
		// 第三方应用id
		paramMap.put("client_id", client_id);
		// 第三方应用secret 公钥加密
		paramMap.put("client_secret", URLEncoder.encode(Encryption.pubEncrypt(pubKey, client_secret), "utf-8"));
		// ncc用户名
		paramMap.put("username", username);
		// 密码 公钥加密
		paramMap.put("password", URLEncoder.encode(Encryption.pubEncrypt(pubKey, pwd), "utf-8"));
		// 账套编码
		paramMap.put("biz_center", busi_center);
		// 签名
		String sign = SHA256Util.getSHA256(client_id + client_secret + username + pwd + pubKey);
		paramMap.put("signature", sign);

		String url = baseUrl + "/nccloud/opm/accesstoken";
		String mediaType = "application/x-www-form-urlencoded";
		String token = doPost(url, paramMap, mediaType, null, "");
		return token;
	}

	/**
	 * 测试api
	 * 请求openapi
	 *
	 * @param token 请求body参数加密压缩用的key
	 * @throws Exception 异常
	 */
	private static void testApi(String token) throws Exception {
		// token转对象，获取api访问所用token和secret
		ResultMessageUtil returnData = new Gson().fromJson(token, ResultMessageUtil.class);
		Map<String, String> data = (Map<String, String>) returnData.getData();
		String access_token = data.get("access_token");
		String security_key = data.get("security_key");
		String refresh_token = data.get("refresh_token");
		System.out.println("【ACCESS_TOKEN】:" + access_token);

		// 请求路径
		String url = baseUrl + apiUrl;
		// header 参数
		Map<String,String> headermap = new HashMap<>();
		headermap.put("access_token", access_token);
		headermap.put("client_id", client_id);
		
		StringBuffer sb = new StringBuffer();
		sb.append(client_id);
		if (StringUtils.isNotBlank(requestBody)) {
			// sb.append(requestBody.replaceAll("\\s*|\t|\r|\n", "").trim());
			sb.append(requestBody);
		}
		sb.append(pubKey);
		String sign = SHA256Util.getSHA256(sb.toString());
		headermap.put("signature", sign);

		if (StringUtils.isNotBlank(busi_id)) {
			headermap.put("busi_id", busi_id);
		}
		if (StringUtils.isNotBlank(repeat_check)) {
			headermap.put("repeat_check", repeat_check);
		}
		headermap.put("ucg_flag", "y");

		String mediaType = "application/json;charset=utf-8";

		// 表体数据json
		// 根据安全级别选择加密或压缩请求表体参数
		String json = dealRequestBody(requestBody, security_key, secret_level);

		// 返回值
		String result = doPost(url, null, mediaType, headermap, json);
		String result2DecryptAndDecompress = dealResponseBody(result, security_key, secret_level);
		System.out.println("【RESULT】:" + result);
		// System.out.println("result解密:" + result2);
	}

	/**
	 * 交易响应主体
	 * 返回值进行过加密和压缩，对返回值进行解压和解密
	 *
	 * @param source       源
	 * @param security_key 安全的关键
	 * @param level        水平
	 * @return {@link String}
	 * @throws Exception 异常
	 */
	private static String dealResponseBody(String source, String security_key, String level) throws Exception {
		String result = null;

		if (StringUtils.isEmpty(level) || SecretConst.LEVEL0.equals(level)) {
			result = source;
		} else if (SecretConst.LEVEL1.equals(level)) {
			result = Decryption.symDecrypt(security_key, source);
		} else if (SecretConst.LEVEL2.equals(level)) {
			result = CompressUtil.gzipDecompress(source);
		} else if (SecretConst.LEVEL3.equals(level)) {
			result = CompressUtil.gzipDecompress(Decryption.symDecrypt(security_key, source));
		} else if (SecretConst.LEVEL4.equals(level)) {
			result = Decryption.symDecrypt(security_key, CompressUtil.gzipDecompress(source));
		} else {
			throw new Exception("无效的安全等级");
		}

		return result;
	}

	/**
	 * 初始化
	 * 初始化参数
	 */
	private static void init() {
		// TODO Auto-generated method stub
		Properties properties = new Properties();

		String filepath = "config.properties";
		ClassLoader classloader = Thread.currentThread().getContextClassLoader();
		InputStream inputStream = classloader.getResourceAsStream(filepath);
		try {
			InputStreamReader reader = new InputStreamReader(inputStream, "UTF-8");
			properties.load(reader);

			client_secret = new String(properties.getProperty("client_secret").getBytes("utf-8"), "utf-8");
			client_id = properties.getProperty("client_id");
			pubKey = properties.getProperty("pubKey");
			username = properties.getProperty("username");
			pwd = properties.getProperty("pwd");
			busi_center = properties.getProperty("busi_center");
			baseUrl = properties.getProperty("baseUrl");
			requestBody = new String(properties.getProperty("requestBody").getBytes("utf-8"), "utf-8");
			apiUrl = properties.getProperty("apiUrl");
			grant_type = properties.getProperty("grant_type");
			secret_level = properties.getProperty("secret_level");
			repeat_check = properties.getProperty("repeat_check");
			busi_id = properties.getProperty("busi_id");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 交易请求体
	 *
	 * @param source       源
	 * @param security_key 安全的关键
	 * @param level        水平
	 * @return {@link String}
	 * @throws Exception 异常
	 */// 根据安全级别设置，表体是否加密或压缩
	private static String dealRequestBody(String source, String security_key, String level) throws Exception {
		String result = null;
		if (StringUtils.isEmpty(level) || SecretConst.LEVEL0.equals(level)) {
			result = source;
		} else if (SecretConst.LEVEL1.equals(level)) {
			result = Encryption.symEncrypt(security_key, source);
		} else if (SecretConst.LEVEL2.equals(level)) {
			result = CompressUtil.gzipCompress(source);
		} else if (SecretConst.LEVEL3.equals(level)) {
			result = Encryption.symEncrypt(security_key, CompressUtil.gzipCompress(source));
		} else if (SecretConst.LEVEL4.equals(level)) {
			result = CompressUtil.gzipCompress(Encryption.symEncrypt(security_key, source));
		} else {
			throw new Exception("无效的安全等级");
		}

		return result;
	}

	/**
	 * 做帖子
	 * 发送post请求
	 *
	 * @param baseUrl   基url
	 * @param paramMap  参数映射
	 * @param mediaType 媒体类型
	 * @param headers   头
	 * @param json      json
	 * @return {@link String}
	 */
	private static String doPost(String baseUrl, Map<String, String> paramMap, String mediaType, Map<String, String> headers, String json) {
		
		HttpURLConnection urlConnection = null;
		InputStream in = null;
		OutputStream out = null;
		BufferedReader bufferedReader = null;
		String result = null;
		try {
			StringBuffer sb = new StringBuffer();
			sb.append(baseUrl);
			if (paramMap != null) {
				sb.append("?");
				for (Map.Entry<String, String> entry : paramMap.entrySet()) {
					String key = entry.getKey();
					String value = entry.getValue();
					sb.append(key + "=" + value).append("&");
				}
				baseUrl = sb.toString().substring(0, sb.toString().length() - 1);
			}

			URL urlObj = new URL(baseUrl);
			urlConnection = (HttpURLConnection) urlObj.openConnection();
			urlConnection.setConnectTimeout(50000);
			urlConnection.setRequestMethod("POST");
			urlConnection.setDoOutput(true);
			urlConnection.setDoInput(true);
			urlConnection.setUseCaches(false);
			urlConnection.addRequestProperty("content-type", mediaType);
			if (headers != null) {
				for (String key : headers.keySet()) {
					urlConnection.addRequestProperty(key, headers.get(key));
				}
			}
			out = urlConnection.getOutputStream();
			out.write(json.getBytes("utf-8"));
			out.flush();
			int resCode = urlConnection.getResponseCode();
			if (resCode == HttpURLConnection.HTTP_OK || resCode == HttpURLConnection.HTTP_CREATED || resCode == HttpURLConnection.HTTP_ACCEPTED) {
				in = urlConnection.getInputStream();
			} else {
				in = urlConnection.getErrorStream();
			}
			bufferedReader = new BufferedReader(new InputStreamReader(in, "utf-8"));
			StringBuffer temp = new StringBuffer();
			String line = bufferedReader.readLine();
			while (line != null) {
				temp.append(line).append("\r\n");
				line = bufferedReader.readLine();
			}
			String ecod = urlConnection.getContentEncoding();
			if (ecod == null) {
				ecod = Charset.forName("utf-8").name();
			}
			result = new String(temp.toString().getBytes("utf-8"), ecod);
		} catch (Exception e) {
			System.out.println(e);
		} finally {
			if (null != bufferedReader) {
				try {
					bufferedReader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (null != out) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (null != in) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			urlConnection.disconnect();
		}
		return result;
	}

	class SecretConst {
		/**
		 * LEVEL0 不压缩、不加密
		 */
		public static final String LEVEL0 = "L0";
		/**
		 * LEVEL1 只加密、不压缩
		 */
		public static final String LEVEL1 = "L1";
		/**
		 * LEVEL2 只压缩、不加密
		 */
		public static final String LEVEL2 = "L2";
		/**
		 * LEVEL3 先压缩、后加密
		 */
		public static final String LEVEL3 = "L3";
		/**
		 * LEVEL4 先加密、后压缩
		 */
		public static final String LEVEL4 = "L4";
	}
}
